Skip to content

fix(web): widen folder rail, add right gutter, pill the waiting-since value - #163

Merged
zaridan merged 3 commits into
mainfrom
feat/inbox-list-column-polish
Aug 2, 2026
Merged

fix(web): widen folder rail, add right gutter, pill the waiting-since value#163
zaridan merged 3 commits into
mainfrom
feat/inbox-list-column-polish

Conversation

@zaridan

@zaridan zaridan commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

🟢 SAFE TO MERGE

All four CI checks green on 1fd537e. No new decisions — all ten are sourced and quoted below. CodeRabbit: reviewed the current head (8c42a6b1fd537e, all 6 files), 0 actionable comments, 1 pre-merge warning adjudicated below. Two independent Opus reviews before it: 7 findings total, all real ones fixed.

Decision provenance

Decision — in plain words Source
"Left column" means the folder sidebar, not the Customer column Maintainer instruction, 2026-08-02
Make the folder sidebar wider Maintainer instruction, 2026-08-02
Keep the two right-hand columns right-aligned, but stop them touching the right edge Maintainer instruction, 2026-08-02
Make the waiting-since value stand out Maintainer instruction, 2026-08-02
The rendered result — 220px sidebar, 24px gutter — is approved You, 2026-08-02, after reviewing it running at 1280px: "looks fine now thank you"
Use an outlined pill rather than a filled one Maintainer instruction, 2026-08-02
Fix the badge/pill collision structurally in this PR rather than deferring it Maintainer instruction, 2026-08-02
Use the darker --ht-ink-dim border so the outline clears 3:1, accepting a more definite outline You, 2026-08-02, choosing between three measured options: "Darker border (--ht-ink-dim)"
Leave the badge slot unreserved — pending rows lose ~77px of subject and show none below ~830px window width, rather than every row losing ~62px permanently You, 2026-08-02, choosing between the two measured layouts: "Leave unreserved"
Commit .claude/launch.json so dev servers start from any worktree Maintainer instruction, 2026-08-02

The values 220px and 24px were mine, proposed and then approved on screen rather than specified up front.

No one-way doors. The badge prop is additive and optional; everything else is a CSS value.

What changed

  • Folder rail 190px → 220px (FolderNav.tsx).
  • Right gutter 14px → 24px on the rows, the header band, and the loading skeleton.
  • Waiting-since becomes an outlined pill1px solid var(--ht-ink-dim), no fill.
  • ConversationRow gains a badge slot — optional, unreserved, at the head of the right-hand metadata group. InboxScreen renders the pending StatusPill into it instead of overlaying the row.

Review adjudication

CodeRabbit (on acf64c2, since rebased away): 1 finding — real, fixed. It flagged the right-hand badge area. Its framing was off, but the area was right: the pending badge was overlaying at the old 14px gutter and protruded 10px past everything else.

Independent review #1 (on 70547c2): 4 findings — 2 real and fixed, 1 already resolved, 1 ticketed and now fixed.

Finding Verdict
Waiting-since pill invisible on hover/focus — its fill was the same token as the row's hover background Real, fixed. Confirmed by dispatching the real hover handler: pill and row backgrounds resolved identical.
Loading skeleton still at the old 14px gutter — 10px jitter on every folder switch Real, fixed. Skeleton row now measures 51.00px against the real row's 51.00px.
Pending badge overlaps the waiting-since pill Real. Was ticketed as #164; fixed here via the badge slot. Overlap 63×13px → 0px.
ds/ConversationRow.jsx hand-edited, breaking byte-equality with the design project Already resolved — pushed upstream via DesignSync and read back byte-identical. Not visible from the branch alone.

Independent review #2 (on d408701): 3 real findings + 1 process finding — all addressed.

Finding Verdict
The outline scored only 1.31:1 against the hover background — under WCAG 1.4.11's 3:1, and faintest on the exact row the fix targets. The commit claimed it "cannot be masked." Real, fixed. Claim was an overreach. Border changed to --ht-ink-dim; re-measured in the running app at 4.30:1 at rest, 3.76:1 on hover. Commit message corrected.
Pending rows overflow ~77px earlier than others; below ~830px they show no subject Real, accepted as a deliberate trade — see the provenance table. Recorded rather than silently absorbed.
Changing status in place re-truncates that row's subject while neighbours don't move Same root cause, same accepted trade.
The branch was not actually rebased; origin/main had advanced 4 commits, making git diff origin/main HEAD render as an 11,005-line phantom revert Real, fixed. Rebased onto 8c42a6b. Main touched none of this branch's six files.

Nitpicks accepted: stale time doc comment in the .d.ts, and the JSDoc anatomy comment in the .jsx that omitted the badge slot — both updated. Nitpicks declined: the unused Avatar import (pre-existing, and ds/ must not be hand-fixed); physical vs logical padding (pre-existing across the whole ds/ tree); the flex: 1 header/row minWidth drift (pre-existing).

Confirmed clean by review #2 and worth recording: pill box unchanged at 77.28×17.00, row height unchanged at 51.00px, removing position: relative is safe (nothing in the subtree is absolutely positioned; scrollIntoView is position-agnostic), StatusPill cannot stretch/shrink/wrap as a flex child, badge={null} leaves no phantom gap, and the 36/44/96 columns still align between badge and non-badge rows and against the header band.

Gates

Gate Result
biome check . ✅ exit 0 — 317 files, 1 pre-existing config-migration info
tsc --noEmit (engine) ✅ exit 0
tsc -p web/tsconfig.json ✅ exit 0
vitest run ✅ exit 0 — 87 files, 1742 tests

Rebased onto origin/main at 8c42a6b.

Design-system reconcile

ConversationRow.jsx, its .d.ts, and its .prompt.md are pushed to the Helpthread design project. The prompt doc records both the badge slot and why the border is --ht-ink-dim rather than the obvious --ht-border, so the measurement that made the obvious token wrong is not lost.

FolderNav.tsx and InboxScreen.tsx are app screens with API wiring and have no counterpart in components/app/ yet. FolderNav is shell chrome and belongs there eventually — separate work, not silently skipped.

Scope note

CodeRabbit's "Out of Scope Changes" pre-merge check warns that the folder rail, the pill, and .claude/launch.json fall outside issue #164's objective.

Adjudicated as half correct. The substance is wrong — this PR was never scoped to #164. The inbox column work came first; #164 was discovered during it, filed as a follow-up, then fixed here on the maintainer's instruction rather than deferred. But the framing was misleading: a bare "Closes #164" reads as though the issue were the PR's purpose. Corrected below.

.claude/launch.json genuinely is unrelated to inbox layout — flagged independently by two reviewers, and kept here at the maintainer's explicit request ("yes commit the launch.json too").

Fixes #164 as a side-effect of the badge-slot change; the issue is not this PR's purpose.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The changes update inbox spacing, render conversation badges within reserved row slots, conditionally style conversation times, and add npm-based API and web debug launch configurations.

Changes

Inbox presentation

Layer / File(s) Summary
Inbox layout spacing
web/src/components/FolderNav.tsx, web/src/components/InboxScreen.tsx, web/src/app/(shell)/inbox/[folder]/loading.tsx
The sidebar width increases. Inbox toolbars and loading rows receive additional right padding.
Conversation row layout
web/src/components/ds/inbox/ConversationRow.jsx, web/src/components/ds/inbox/ConversationRow.d.ts, web/src/components/InboxScreen.tsx
ConversationRow adds a badge slot and reserves a right-aligned time slot. Pending conversations pass their status badge through the new slot instead of using an absolute overlay.

Debug launch configuration

Layer / File(s) Summary
Local debug targets
.claude/launch.json
Adds npm-based API and web debug configurations for ports 8787 and 3000.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes unrelated folder rail, waiting-since pill, and .claude/launch.json changes beyond the linked issue's pending badge layout objective [#164]. Move unrelated layout and development-launcher changes into separate PRs, or link issues that explicitly cover those objectives.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR replaces the pending badge overlay with a ConversationRow badge slot that participates in the row layout and updates related component declarations [#164].
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main inbox layout changes: a wider folder rail, increased right gutter, and pill styling for the waiting-since value.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/inbox-list-column-polish

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/src/components/ds/inbox/ConversationRow.jsx`:
- Around line 43-45: Update ConversationRow’s right-aligned badge area around
the time span so the waiting-time pill and the pending status pill have separate
reserved space and cannot overlap. Use a shared right-side flex layout or
otherwise reserve room for the pending pill positioned by InboxScreen, while
preserving the existing time display styling and alignment.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 755a899f-6e6d-4679-9fba-f1d532b47a96

📥 Commits

Reviewing files that changed from the base of the PR and between f2dfbd1 and acf64c2.

📒 Files selected for processing (4)
  • .claude/launch.json
  • web/src/components/FolderNav.tsx
  • web/src/components/InboxScreen.tsx
  • web/src/components/ds/inbox/ConversationRow.jsx

Comment thread web/src/components/ds/inbox/ConversationRow.jsx
zaridan added a commit that referenced this pull request Jul 25, 2026
The pending StatusPill is absolutely positioned over the row and was still
pinned at right: 14 — the old gutter — so it protruded 10px past every other
right-hand element once the gutter moved to 24.

Caught by CodeRabbit on #163 and confirmed in the running app: with a
conversation set to pending, the badge sat 14px from the viewport edge while
the waiting-since pill sat at 24px. Both now measure 24px.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
zaridan added a commit that referenced this pull request Jul 25, 2026
The pending StatusPill is absolutely positioned over the row and was still
pinned at right: 14 — the old gutter — so it protruded 10px past every other
right-hand element once the gutter moved to 24.

Caught by CodeRabbit on #163 and confirmed in the running app: with a
conversation set to pending, the badge sat 14px from the viewport edge while
the waiting-since pill sat at 24px. Both now measure 24px.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@zaridan
zaridan force-pushed the feat/inbox-list-column-polish branch from 6b6b9da to 53b9ea0 Compare July 25, 2026 15:49
zaridan added a commit that referenced this pull request Jul 25, 2026
The pending StatusPill is absolutely positioned over the row and was still
pinned at right: 14 — the old gutter — so it protruded 10px past every other
right-hand element once the gutter moved to 24.

Caught by CodeRabbit on #163 and confirmed in the running app: with a
conversation set to pending, the badge sat 14px from the viewport edge while
the waiting-since pill sat at 24px. Both now measure 24px.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@zaridan
zaridan force-pushed the feat/inbox-list-column-polish branch from 53b9ea0 to 70547c2 Compare July 25, 2026 15:49
@zaridan

zaridan commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@zaridan

zaridan commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 20 minutes.

@zaridan

zaridan commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 39 minutes.

zaridan added a commit that referenced this pull request Aug 2, 2026
The pending StatusPill is absolutely positioned over the row and was still
pinned at right: 14 — the old gutter — so it protruded 10px past every other
right-hand element once the gutter moved to 24.

Caught by CodeRabbit on #163 and confirmed in the running app: with a
conversation set to pending, the badge sat 14px from the viewport edge while
the waiting-since pill sat at 24px. Both now measure 24px.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
zaridan added a commit that referenced this pull request Aug 2, 2026
…ce pill

Two defects found by an independent review of #163, both verified in the
running app before and after the fix.

1. The waiting-since pill was invisible on hover and on the keyboard-focused
   row. Its fill was var(--ht-surface-2) — the exact token the row already
   uses for both states — so the pill's shape vanished on whichever row the
   Agent was looking at. The count chip has the same fill but only renders
   when a thread has more than one message, so it never showed the problem.
   The pill is now an outline (1px var(--ht-border), no fill, padding
   1px 7px to keep the outer box the same size), which cannot be masked by
   any row background.

2. The pending StatusPill was an absolutely-positioned overlay at right: 24,
   landing on top of the waiting-since pill. ConversationRow now takes a
   `badge` slot, rendered inline at the head of the right-hand group, and
   InboxScreen passes the StatusPill into it. Measured overlap with the time
   pill: 0px, down from 63px wide by 13px tall. The slot has no reserved
   width, so rows without a badge are unaffected; the row wrapper's
   position: relative went with the overlay it existed to anchor.

Also updates the inbox loading skeleton, which still had the old 14px right
gutter and would have jittered 10px on every folder switch.

This closes #164 rather than deferring it.

ConversationRow.jsx, its .d.ts, and its .prompt.md were pushed to the
Helpthread design project and read back byte-identical — the badge slot is a
design-system API addition, not just a style change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@zaridan
zaridan force-pushed the feat/inbox-list-column-polish branch from 70547c2 to d408701 Compare August 2, 2026 17:56
@zaridan

zaridan commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 31 minutes.

zaridan and others added 3 commits August 2, 2026 11:23
… value

Inbox list column polish, from a side-by-side review of the list surface:

- Folder rail 190px -> 220px, so labels and counts stop crowding.
- Right gutter 14px -> 24px on both the conversation rows and the header
  band. The Number and Waiting-since columns stay right-aligned; they were
  simply flush against the content edge with no breathing room.
- The waiting-since value becomes a rounded pill, reusing the same chip
  treatment as the message-count badge one column over rather than
  introducing a new one. Measured against `relativeTime`'s widest possible
  output ("Mar 14, 2025", 91px) — fits the 96px column with room to spare.

ConversationRow.jsx is a design-system file, so the same change was pushed
back up to the Helpthread design project (components/inbox/ConversationRow.jsx)
and read back byte-identical, per the app -> design reconcile rule in
CLAUDE.md. The folder rail and header band live in app screens that have no
upstream counterpart yet, so nothing to reconcile there.

Also adds .claude/launch.json so the web and API dev servers are startable
from any worktree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The pending StatusPill is absolutely positioned over the row and was still
pinned at right: 14 — the old gutter — so it protruded 10px past every other
right-hand element once the gutter moved to 24.

Caught by CodeRabbit on #163 and confirmed in the running app: with a
conversation set to pending, the badge sat 14px from the viewport edge while
the waiting-since pill sat at 24px. Both now measure 24px.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ce pill

Two defects found by independent review of #163, both verified in the running
app before and after the fix.

1. The waiting-since pill was invisible on hover and on the keyboard-focused
   row. Its fill was var(--ht-surface-2) — the exact token the row already
   uses for both states — so the pill's shape vanished on whichever row the
   Agent was looking at. The count chip has the same fill but only renders
   when a thread has more than one message, so it never showed the problem.
   The pill is now an outline (1px, no fill, padding 1px 7px to keep the
   outer box the same size — measured 77.28 x 17.00 before and after).

   The outline is var(--ht-ink-dim), NOT var(--ht-border). The obvious token
   is the wrong one: --ht-border measures 1.3:1 against the hover background
   and effectively disappears on exactly the row this fix exists for.
   --ht-ink-dim measures 4.30:1 at rest and 3.76:1 on hover, clearing
   WCAG 1.4.11's 3:1 for a component boundary in both themes.

2. The pending StatusPill was an absolutely-positioned overlay at right: 24,
   landing on top of the waiting-since pill. ConversationRow now takes a
   `badge` slot, rendered inline at the head of the right-hand group, and
   InboxScreen passes the StatusPill into it. Measured overlap with the time
   pill: 0px, down from 63px wide by 13px tall. The row wrapper's
   position: relative went with the overlay it existed to anchor.

   The slot has no reserved width. That is a deliberate trade: rows without a
   badge keep their full subject column, and rows with one lose ~77px. Below
   roughly 830px of window width a pending row shows no subject text while
   its neighbours still do. Reserving a fixed slot would spread that cost
   evenly across every row instead; the maintainer chose the unreserved slot.

Also updates the inbox loading skeleton, which still had the old 14px right
gutter and would have jittered 10px on every folder switch. Measured 51.00px
per skeleton row against 51.00px per real row.

This closes #164 rather than deferring it.

ConversationRow.jsx, its .d.ts, and its .prompt.md were pushed to the
Helpthread design project — the badge slot is a design-system API addition,
and the prompt doc records why the border token is --ht-ink-dim so the
"obvious" value does not get restored later as a bug.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@zaridan
zaridan force-pushed the feat/inbox-list-column-polish branch from d408701 to 1fd537e Compare August 2, 2026 18:37
@zaridan

zaridan commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@zaridan
zaridan merged commit 445a245 into main Aug 2, 2026
5 checks passed
@zaridan
zaridan deleted the feat/inbox-list-column-polish branch August 2, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pending badge overlays the waiting-since cell instead of having its own column

1 participant